import re
import pickle
import traceback

class Serializer:
    def __init__(self, instance=None, extra_dict=None):
        '''
            序列化一个对象，使得它能够被pickle打包并发送给另一个进程
            解决多进程不能传送execution实例问题
            缺陷：会丢失不能序列化的属性
        '''
        self.cannot_serialize = {}
        self.to_serializer(instance, extra_dict)
    
    def to_serializer(self, instance, extra_dict):
        if instance:
            # for attr in instance.__dict__:
            for attr in dir(instance):
                if not re.search(r"^_", attr) and attr!="serializer": 
                    try:
                        value = getattr(instance, attr)
                        self.set_attr(attr, value)
                    except:
                        pass
        if isinstance(extra_dict, dict):
            for k, v in extra_dict.items():
                self.set_attr(k, v)
    
    def filter_dict_list(self, ins):
        if isinstance(ins, tuple):
            ins = list(ins)
        if isinstance(ins, dict):
            ret = {}
            for k, v in ins.items():
                if not self.is_serialize(k):
                    continue
                if not self.is_serialize(v):
                    if isinstance(v, dict) or isinstance(v, list):
                        new_v = self.filter_dict_list(v)
                        ret[k] = new_v
                else:
                    ret[k] = v
        elif isinstance(ins, list):
            ret = []
            for v in ins:
                if not self.is_serialize(v):
                    if isinstance(v, dict) or isinstance(v, list):
                        ret.append(self.filter_dict_list(v))
                else:
                    ret.append(v)
            ins = ret
        else:
            raise Exception("请传入字典或者列表")
        return ret
                    
    def set_attr(self, k, v):
        if self.is_serialize(v):
            setattr(self, k, v)
        else:
            if (isinstance(v, dict) or isinstance(v, list) or isinstance(v, tuple)) and self.is_serialize(k):
                try:
                    new_v = self.filter_dict_list(v)
                except:
                    print("序列化报错"+str(k)+str(traceback.format_exc()))
                setattr(self, k, new_v)
            else:
                self.cannot_serialize[str(k)] = str(type(v))
                
    def is_serialize(self, v):
        try:
            pickle.dumps(v)
            return True
        except:
            return False